package com.xzy.c;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor;
import org.springframework.beans.factory.config.SmartInstantiationAwareBeanPostProcessor;
import org.springframework.beans.factory.support.AbstractBeanDefinition;

/**
 * 说明：Bean生命周期之实例化前
 *
 * @author xzy
 * @date 2021/12/5 14:37
 */
@Slf4j
public class MyInstantiationAwareBeanPostProcessor implements InstantiationAwareBeanPostProcessor {

    /**
     * Apply this BeanPostProcessor <i>before the target bean gets instantiated</i>.
     * The returned bean object may be a proxy to use instead of the target bean,
     * effectively suppressing default instantiation of the target bean.
     * <p>If a non-null object is returned by this method, the bean creation process
     * will be short-circuited. The only further processing applied is the
     * {@link #postProcessAfterInitialization} callback from the configured
     * {@link BeanPostProcessor BeanPostProcessors}.
     * <p>This callback will be applied to bean definitions with their bean class,
     * as well as to factory-method definitions in which case the returned bean type
     * will be passed in here.
     * <p>Post-processors may implement the extended
     * {@link SmartInstantiationAwareBeanPostProcessor} interface in order
     * to predict the type of the bean object that they are going to return here.
     * <p>The default implementation returns {@code null}.
     *
     * @param beanClass the class of the bean to be instantiated
     * @param beanName  the name of the bean
     * @return the bean object to expose instead of a default instance of the target bean,
     * or {@code null} to proceed with default instantiation
     * @throws BeansException in case of errors
     * @see #postProcessAfterInstantiation
     * @see AbstractBeanDefinition#getBeanClass()
     * @see AbstractBeanDefinition#getFactoryMethodName()
     */
    @Override
    public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
        log.info("实例化前 => beanClass={},beanName={}", beanClass, beanName);

        /*
         * Bean创建生命周期节点：
         *
         *             ↓
         * [开始]-->[实例化前]-->[实例化]-->[实例化后]-->[依赖注入]-->[初始化前]-->[初始化]-->[初始化后]-->Bean
         *
         *
         * 此方法如果返回对象，那么将跳过后面的流程，并且直接将返回的对象作为Bean：
         *
         * [开始]-->[实例化前]-->[实例化]-->[实例化后]-->[依赖注入]-->[初始化前]-->[初始化]-->[初始化后]-->Bean
         *             ↓                                                                         ↑
         *             ---------------------------------------------------------------------------
         */

        // return new Object();
        return null;
    }
}
